// <!--
//  * 严肃声明：
//  * 开源版本请务必保留此注释头信息，若删除我方将保留所有法律责任追究！
//  * 可正常分享和学习源码，不得用于违法犯罪活动，违者必究！
//  * Copyright (c) 2022 APThink David唐 all rights reserved.
//  * 版权所有，侵权必究！
//  *
// -->
import instance from "./base"
import { isEmpty, json2object, notification } from "@/utils"
import {i18n} from "@/i18n"
import log from "loglevel"

/**
 * @param {String} method  请求的方法：get、post、delete、put
 * @param {String} url     请求的url:
 * @param {Object} data    请求的参数
 * @param {Object} config  请求的配置
 * @returns {Promise}     返回一个promise对象，其实就相当于axios请求数据的返回值
 */
function request(o: { method: string, url: string, data?: string | object | null }) {
  const m = o.method.toLowerCase();
  if (m == "post") {
    return instance.post(o.url, o.data);
  } else if (m == "get") {
    return instance.get(o.url, {
      params: o.data,
    });
  } else if (m == "delete") {
    return instance.delete(o.url, {
      params: o.data,
    });
  } else if (o.method == "put") {
    return instance.put(o.url, o.data);
  } else {
    log.error("未知的method:" + o.method);
    return instance.post(o.url, o.data);
  }
}

//请求示例
//get
export function get(url: string, data?: object) {
  // return new Promise((resolve, reject) => {
  return new Promise((resolve) => {
    request({
      url: url,
      method: "get",
      data: data,
    }).then((res: any) => {
        resolve(res.data);
      })
      .catch((e: any) => {
        log.debug(e);
        // reject(e);
      });
  });
}

//post
export function post(url: string, data?: string| object) {
  // return new Promise((resolve, reject) => {
  return new Promise((resolve) => {
    request({
      url: url,
      method: "post",
      data: data,
    })
      .then((res: any) => {
        resolve(res.data);
      })
      .catch((e: any) => {
        log.debug(e);
        // reject(e);
      });
  });
}

function _setFieldApi(data: Array<string>, apis: Array<any>, results:Array<any>) {
  data.forEach((x) => {
    apis.push(
      request({
        url: "/userparameter",
        method: "post",
        data: x,
      })
    );
    apis.push(
      request({
        url: "/systemparameter",
        method: "post",
        data: x,
      })
    );
    results.push({});
    results.push({});
  });
}

function _setAllApi(data: Array<string>, apis: Array<any>, results:Array<any>) {
  data.forEach((x) => {
    apis.push(
      request({
        url: "/" + x + "/all",
        method: "get"
      })
    );
    results.push({});
  });
}

function _setBaseDataApi(data: Array<string>, apis: Array<any>, results:Array<any>) {
  data.forEach((x) => {
    apis.push(
      request({
        url: "/basedatas",
        method: "post",
        data: x,
      })
    );
    results.push({});
  });
}

function _setSysDataApi(data: Array<string>, apis: Array<any>, results:Array<any>) {
  data.forEach((x) => {
    apis.push(
      request({
        url: "/sysdata",
        method: "post",
        data: x,
      })
    );
    results.push({});
  });
}

function _setSysParameterApi(data: Array<string>, apis: Array<any>, results:Array<any>) {
    apis.push(
      request({
        url: "/systemparameters",
        method: "post",
        data: data,
      })
    );
    results.push({});
}

function _setUserParameterApi(data: Array<string>, apis: Array<any>, results:Array<any>) {
    apis.push(
      request({
        url: "/userparameters",
        method: "post",
        data: data,
      })
    );
    results.push({});
}

function _setUrlApi(data: Array<string>, apis: Array<any>, results:Array<any>) {
  data.forEach((x) => {
    apis.push(
      request({
        url: x,
        method: "get"
      })
    );
    results.push({});
  });
}

function _setPostApi(data: Array<any>, apis: Array<any>, results:Array<any>) {
  data.forEach((x) => {
    apis.push(
      request({
        url: x.url,
        method: "post",
        data: x.data,
      })
    );
    results.push({});
  });
}

function _setFieldResult(data: Map<string, object>, names: Array<string>, results: Array<any>, startIndex?: number) {
  const sIndex = startIndex || 0;
  const userFields = new Map();
  const allFields = new Map();
  for (let i = 0; i < names.length; i++) {
    const rIndex = sIndex + i * 2;
    const a = json2object(results[rIndex + 1].data);
    allFields.set(names[i], a);
    let f = results[rIndex].data;
    if (!isEmpty(f)) {
      f = json2object(f);
    } else {
      f = a;
    }
    userFields.set(names[i], f);
  }
  data.set("allfields", allFields);
  data.set("userfields", userFields);
}

function _setUrlResult(data:Map<string, object>, urls: Array<string>, results:Array<any>, startIndex?:number, name?: string) {
  const sIndex = startIndex || 0;
  const resultMap = new Map();
  for (let i = 0; i < urls.length; i++) {
    resultMap.set(i, results[sIndex + i].data);
  }
  if (name) {
    data.set(name, resultMap);
  } else {
    resultMap.forEach((value, key) => {
      data.set(key, value);
    });
  }
}

function _setResult(data:Map<string, object>, tables: Array<string>, results: Array<any>, startIndex?: number, name?:string) {
  const sIndex = startIndex || 0;
  const resultMap = new Map();
  for (let i = 0; i < tables.length; i++) {
    resultMap.set(tables[i], results[sIndex + i].data);
  }
  if (name) {
    data.set(name, resultMap);
  } else {
    resultMap.forEach((value, key) => {
      data.set(key, value);
    });
  }
}

//David：根据查询api生成规则返回结果起始位置
function _getResultIndex(apidata: Array<any>, index: number) {
  let result = 0;
  for (let i = 0; i < index; i++) {
    const x = apidata[i];
    if (x.type == "field") {
      result += x.data.length * 2;
    } else {
      result += x.data.length;
    }
  }
  return result;
}

//David: 生成查询url集合和解析返回结果必须保持相同顺序
export function all(apidata: Array<any>) {
  // return new Promise((resolve, reject) => {
  return new Promise((resolve) => {
    const apis: Array<any>=[];
    const results:Array<any>=[];
    for (let i = 0; i < apidata.length; i++) {
      const x = apidata[i];
      if (x.type == "field") {
        _setFieldApi(x.data, apis, results);
      } else if (x.type == "table") {
        _setAllApi(x.data, apis, results);
      } else if (x.type == "sysparam") {
        _setSysParameterApi(x.data, apis, results);
      } else if (x.type == "userparam") {
        _setUserParameterApi(x.data, apis, results);
      } else if (x.type == "basedata") {
        _setBaseDataApi(x.data, apis, results);
      } else if (x.type == "sysdata") {
        _setSysDataApi(x.data, apis, results);
      } else if (x.type == "post") {
        _setPostApi(x.data, apis, results);
      } else {
        _setUrlApi(x.data, apis, results);
      }
    }
    instance
      .all(apis)
      .then(
        instance.spread((...results) => {
          const data = new Map();
          for (let i = 0; i < apidata.length; i++) {
            const x = apidata[i];
            if (x.type == "field") {
              _setFieldResult(
                data,
                x.data,
                results,
                _getResultIndex(apidata, i),
              );
            } else if (x.type == "url" || x.type == "post") {
              _setUrlResult(
                data,
                x.data,
                results,
                _getResultIndex(apidata, i),
                x.type
              );
            } else {
              _setResult(
                data,
                x.data,
                results,
                _getResultIndex(apidata, i),
                x.type
              );
            }
          }
          resolve(data);
        })
      )
      .catch((e) => {
        log.debug(e);
        // reject(e);
      });
  });
}

export function add(table: string, data: object) {
  // log.debug(table, data);
  const url = "/" + table + "/add";
  // return new Promise((resolve, reject) => {
  return new Promise((resolve) => {
    request({
      url: url,
      method: "post",
      data,
    })
      .then((res) => {
        notification(i18n.global.t("table."+table), i18n.global.t("message.addok"));
        resolve(res.data);
      })
      .catch((e) => {
        log.debug(e);
        // reject(e);
      });
  });
}

export function del(table: string, id: string) {
  const url = "/" + table + "/delete";
  const data = { id: id };
  // return new Promise((resolve, reject) => {
  return new Promise((resolve) => {
    request({
      url: url,
      method: "post",
      data,
    })
      .then((res) => {
        notification(i18n.global.t("table."+table), i18n.global.t("message.deleteok"));
        resolve(res.data);
      })
      .catch((e) => {
        log.debug(e);
        // reject(e);
      });
  });
}

export function upd(table: string, data: object) {
  const url = "/" + table + "/update";
  // return new Promise((resolve, reject) => {
  return new Promise((resolve) => {
    request({
      url: url,
      method: "post",
      data,
    })
      .then((res) => {
        notification(i18n.global.t("table."+table), i18n.global.t("message.updateok"));
        resolve(res.data);
      })
      .catch((e) => {
        log.debug(e);
        // reject(e);
      });
  });
}

export function query(table: string, data: object) {
  const url = "/" + table + "/query";
  // return new Promise((resolve, reject) => {
  return new Promise((resolve) => {
    request({
      url: url,
      method: "post",
      data,
    })
      .then((res) => {
        notification(i18n.global.t("table."+table), i18n.global.t("message.queryok"));
        resolve(res.data);
      })
      .catch((e) => {
        log.debug(e);
        // reject(e);
      });
  });
}

export function copy(table: string, data: object) {
  const url = "/" + table + "/copy";
  return new Promise((resolve) => {
    // return new Promise((resolve, reject) => {
    request({
      url: url,
      method: "post",
      data,
    })
      .then((res) => {
        notification(i18n.global.t("table."+table), i18n.global.t("message.copyok"));
        resolve(res.data);
      })
      .catch((e) => {
        log.debug(e);
        // reject(e);
      });
  });
}

export function tables(names: string[]) {
  log.debug(tables);
  return new Promise((resolve, reject) => {
    const apis: Array<any>=[];
    const results: Array<any>=[];
    _setAllApi(names, apis, results);
    instance.all(apis)
      .then(instance.spread((...results) => {
        const data = new Map();
        _setResult(data, names, results);
        log.debug(data);
        resolve(data);
      }))
      .catch(e => {
        log.debug(e);
        reject(e);
      });
  });
}

export function sysparam(param : string[] | string) {
  log.debug(param);
  if (param instanceof Array) {
    return post("/systemparameters", param);
  } else {
    return post("/systemparameter", param);
  }
}

export function userparam(param: Array<string> | string) {
  log.debug(param);
  if (param instanceof Array) {
    return post("/userparameters", param);
  } else {
    return post("/userparameter", param);
  }
}

export function field(names: Array<string>) {
  log.debug(names);
  return new Promise((resolve, reject) => {
    const apis: Array<any>=[];;
    const results: Array<any>=[];;
    _setFieldApi(names, apis, results);
    instance.all(apis)
      .then(instance.spread((...results) => {
        const data = new Map();
        _setFieldResult(data, names, results);
        log.debug(data);
        resolve(data);
      }))
      .catch(e => {
        log.debug(e);
        reject(e);
      });
  });
}

export function url(urls: string[]) {
  log.debug(urls);
  return new Promise((resolve, reject) => {
    const apis: Array<any>=[];
    const results: Array<any>=[];
    _setUrlApi(urls, apis, results);
    instance.all(apis)
      .then(instance.spread((...results) => {
        const data = new Map();
        _setUrlResult(data, urls, results);
        log.debug(data);
        resolve(data);
      }))
      .catch(e => {
        log.debug(e);
        reject(e);
      });
  });
}
